linux/fs/isofs/namei.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/isofs/namei.c
   3 *
   4 *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
   5 *
   6 *  (C) 1991  Linus Torvalds - minix filesystem
   7 */
   8
   9#include <linux/gfp.h>
  10#include "isofs.h"
  11
  12/*
  13 * ok, we cannot use strncmp, as the name is not in our data space.
  14 * Thus we'll have to use isofs_match. No big problem. Match also makes
  15 * some sanity tests.
  16 */
  17static int
  18isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
  19{
  20        struct qstr qstr;
  21
  22        if (!compare)
  23                return 1;
  24
  25        /* check special "." and ".." files */
  26        if (dlen == 1) {
  27                /* "." */
  28                if (compare[0] == 0) {
  29                        if (!dentry->d_name.len)
  30                                return 0;
  31                        compare = ".";
  32                } else if (compare[0] == 1) {
  33                        compare = "..";
  34                        dlen = 2;
  35                }
  36        }
  37
  38        qstr.name = compare;
  39        qstr.len = dlen;
  40        return dentry->d_op->d_compare(NULL, NULL, NULL, NULL,
  41                        dentry->d_name.len, dentry->d_name.name, &qstr);
  42}
  43
  44/*
  45 *      isofs_find_entry()
  46 *
  47 * finds an entry in the specified directory with the wanted name. It
  48 * returns the inode number of the found entry, or 0 on error.
  49 */
  50static unsigned long
  51isofs_find_entry(struct inode *dir, struct dentry *dentry,
  52        unsigned long *block_rv, unsigned long *offset_rv,
  53        char *tmpname, struct iso_directory_record *tmpde)
  54{
  55        unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
  56        unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
  57        unsigned long block, f_pos, offset, block_saved, offset_saved;
  58        struct buffer_head *bh = NULL;
  59        struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
  60
  61        if (!ISOFS_I(dir)->i_first_extent)
  62                return 0;
  63
  64        f_pos = 0;
  65        offset = 0;
  66        block = 0;
  67
  68        while (f_pos < dir->i_size) {
  69                struct iso_directory_record *de;
  70                int de_len, match, i, dlen;
  71                char *dpnt;
  72
  73                if (!bh) {
  74                        bh = isofs_bread(dir, block);
  75                        if (!bh)
  76                                return 0;
  77                }
  78
  79                de = (struct iso_directory_record *) (bh->b_data + offset);
  80
  81                de_len = *(unsigned char *) de;
  82                if (!de_len) {
  83                        brelse(bh);
  84                        bh = NULL;
  85                        f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
  86                        block = f_pos >> bufbits;
  87                        offset = 0;
  88                        continue;
  89                }
  90
  91                block_saved = bh->b_blocknr;
  92                offset_saved = offset;
  93                offset += de_len;
  94                f_pos += de_len;
  95
  96                /* Make sure we have a full directory entry */
  97                if (offset >= bufsize) {
  98                        int slop = bufsize - offset + de_len;
  99                        memcpy(tmpde, de, slop);
 100                        offset &= bufsize - 1;
 101                        block++;
 102                        brelse(bh);
 103                        bh = NULL;
 104                        if (offset) {
 105                                bh = isofs_bread(dir, block);
 106                                if (!bh)
 107                                        return 0;
 108                                memcpy((void *) tmpde + slop, bh->b_data, offset);
 109                        }
 110                        de = tmpde;
 111                }
 112
 113                dlen = de->name_len[0];
 114                dpnt = de->name;
 115                /* Basic sanity check, whether name doesn't exceed dir entry */
 116                if (de_len < dlen + sizeof(struct iso_directory_record)) {
 117                        printk(KERN_NOTICE "iso9660: Corrupted directory entry"
 118                               " in block %lu of inode %lu\n", block,
 119                               dir->i_ino);
 120                        return 0;
 121                }
 122
 123                if (sbi->s_rock &&
 124                    ((i = get_rock_ridge_filename(de, tmpname, dir)))) {
 125                        dlen = i;       /* possibly -1 */
 126                        dpnt = tmpname;
 127#ifdef CONFIG_JOLIET
 128                } else if (sbi->s_joliet_level) {
 129                        dlen = get_joliet_filename(de, tmpname, dir);
 130                        dpnt = tmpname;
 131#endif
 132                } else if (sbi->s_mapping == 'a') {
 133                        dlen = get_acorn_filename(de, tmpname, dir);
 134                        dpnt = tmpname;
 135                } else if (sbi->s_mapping == 'n') {
 136                        dlen = isofs_name_translate(de, tmpname, dir);
 137                        dpnt = tmpname;
 138                }
 139
 140                /*
 141                 * Skip hidden or associated files unless hide or showassoc,
 142                 * respectively, is set
 143                 */
 144                match = 0;
 145                if (dlen > 0 &&
 146                        (!sbi->s_hide ||
 147                                (!(de->flags[-sbi->s_high_sierra] & 1))) &&
 148                        (sbi->s_showassoc ||
 149                                (!(de->flags[-sbi->s_high_sierra] & 4)))) {
 150                        match = (isofs_cmp(dentry, dpnt, dlen) == 0);
 151                }
 152                if (match) {
 153                        isofs_normalize_block_and_offset(de,
 154                                                         &block_saved,
 155                                                         &offset_saved);
 156                        *block_rv = block_saved;
 157                        *offset_rv = offset_saved;
 158                        brelse(bh);
 159                        return 1;
 160                }
 161        }
 162        brelse(bh);
 163        return 0;
 164}
 165
 166struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 167{
 168        int found;
 169        unsigned long uninitialized_var(block);
 170        unsigned long uninitialized_var(offset);
 171        struct inode *inode;
 172        struct page *page;
 173
 174        page = alloc_page(GFP_USER);
 175        if (!page)
 176                return ERR_PTR(-ENOMEM);
 177
 178        found = isofs_find_entry(dir, dentry,
 179                                &block, &offset,
 180                                page_address(page),
 181                                1024 + page_address(page));
 182        __free_page(page);
 183
 184        inode = found ? isofs_iget(dir->i_sb, block, offset) : NULL;
 185
 186        return d_splice_alias(inode, dentry);
 187}
 188
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.